package com.tools.db.jdbc;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.tools.common.object.Note;

import java.util.LinkedHashMap;

/**
 * 分页抽象类
 * 如果某个数据表的查询需要分页
 * 可以让其实体类继承该类，分页拦截器会
 * 自动加上分页关键字 LIMIT
 * */
@Note("分页抽象类。" +
        "如果某个数据表的查询需要分页，可以让其实体类继承该类，" +
        "分页拦截器会自动加上分页关键字 LIMIT")
public abstract class PagingBean {

    @JsonIgnore
    @Note("当前页码")
    protected int currentPage = 1;

    @JsonIgnore
    @Note("一页展示多少条记录")
    protected int pageSize = 20;

    @JsonIgnore
    @Note("记录总数")
    protected long total;

    @JsonIgnore
    @Note("是否开启自动分页逻辑（为 MyBatis 拦截器所用）")
    protected boolean autoPaging = false;

    @JsonIgnore
    @Note("字段-排序方式的 LinkedHashMap 集合。不为空时就会自动拼接到 SQL 语句上")
    protected LinkedHashMap<String, SortEnum> sortMap;

    /* *******************************************************************************************
     *
     *      构造器
     *
     * *******************************************************************************************
     * */

    protected PagingBean() {}

    @Note("传入当前页码的参数，自动计算偏移量")
    protected PagingBean(int currentPage, int pageSize) {
        this.setPageSize(pageSize);
        this.setCurrentPage(currentPage);
    }

    /* *******************************************************************************************
     *
     *      Getter / Setter
     *
     * *******************************************************************************************
     * */


    @JsonIgnore
    public long getOffset() {
        return calcOffset(currentPage, pageSize);
    }

    @Note("传入当前页码的参数，自动计算偏移量")
    public static long calcOffset(int currentPage, int pageSize) {
        return (long) (currentPage - 1) * pageSize;
    }

    public boolean isAutoPaging() {
        return autoPaging;
    }

    public void enableAutoPaging(boolean autoPaging) {
        this.autoPaging = autoPaging;
    }

    public int getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(int currentPage) {
        if(currentPage < 1) throw new IllegalArgumentException("当前页码最低为第 1 页");
        this.currentPage = currentPage;
    }

    public void setCurrentPage(Integer currentPage) {
        if(currentPage == null) this.currentPage = 1;
        else this.setCurrentPage(currentPage.intValue());
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = Math.max(pageSize, 0);
    }

    public void setPageSize(Integer pageSize) {
        if(pageSize == null) this.pageSize = 20;
        else this.setPageSize(pageSize.intValue());
    }

    public long getTotal() {
        return total;
    }

    public void setTotal(long total) {
        this.total = Math.max(total, 0);
    }

    public void setTotal(Long total) {
        this.total = (total == null) ? 0 : total;
    }

    LinkedHashMap<String, SortEnum> getSortMap() {
        return sortMap;
    }

    public void setSortMap(LinkedHashMap<String, SortEnum> sortMap) {
        synchronized (this) {
            this.sortMap = sortMap;
        }
    }

    /* *******************************************************************************************
     *
     *      链式调用
     *
     * *******************************************************************************************
     * */

    public PagingBean currentPage(int currentPage) {
        this.setCurrentPage(currentPage);
        return this;
    }

    public PagingBean currentPage(Integer currentPage) {
        this.setCurrentPage(currentPage);
        return this;
    }

    public PagingBean autoPaging(boolean autoPaging) {
        this.enableAutoPaging(autoPaging);
        return this;
    }

    public PagingBean pageSize(int pageSize) {
        this.setPageSize(pageSize);
        return this;
    }

    public PagingBean pageSize(Integer pageSize) {
        this.setPageSize(pageSize);
        return this;
    }

    public PagingBean total(long total) {
        this.setTotal(total);
        return this;
    }

    public PagingBean total(Long total) {
        this.setTotal(total);
        return this;
    }

    public PagingBean sortMap(LinkedHashMap<String, SortEnum> sortMap) {
        this.setSortMap(sortMap);
        return this;
    }

    /* *******************************************************************************************
     *
     *      自定义方法
     *
     * *******************************************************************************************
     * */

    public PagingBean addSort(String field, SortEnum sortMethod) {
        if(field == null || field.isEmpty()) throw new NullPointerException("数据库的字段名称不能为空");
        if(sortMethod == null) throw new NullPointerException("排序方式不能为 null");
        private_initSortMap();
        this.sortMap.put(field, sortMethod);
        return this;
    }


    public PagingBean removeSort(String field) {
        if(sortMap == null || sortMap.isEmpty()) return this;
        if(field == null || field.isEmpty()) return this;
        this.sortMap.remove(field);
        return this;
    }

    public boolean containsSort(String field) {
        if(sortMap == null || sortMap.isEmpty()) return false;
        return sortMap.containsKey(field);
    }

    public PagingBean clearSort() {
        if(sortMap == null || sortMap.isEmpty()) return this;
        this.sortMap.clear();
        return this;
    }

    /* *******************************************************************************************
     *
     *      私有逻辑
     *
     * *******************************************************************************************
     * */

    @Note("懒加载 ”字段-排序方式” 的 LinkedHashMap 集合")
    private void private_initSortMap() {
        if(sortMap != null) return;
        synchronized (this) {
            if(sortMap != null) return;
            this.sortMap = new LinkedHashMap<>(2);
        }
    }
}
